#pragma once
#include<iostream>
#include<string>
#include<Windows.h>
#include<list>
#include<locale>
using namespace std;

class WatchFolder {
	HANDLE m_hFile; //进行监视的文件句柄
	char* m_buf; //保存文件信息更改的缓存区
public:
	struct FILE_INFO
	{
		std::wstring name;
		DWORD action;
		FILE_INFO(const wchar_t* fileName, DWORD act) {
			name = fileName;
			action = act;
		}
	};
	//可监视的属性
	enum {
		NOTIFY_FILE_NAME = FILE_NOTIFY_CHANGE_FILE_NAME, //监视文件名更改
		NOTIFY_DIR_NAME = FILE_NOTIFY_CHANGE_DIR_NAME, //监视目录名更改
		NOTIFY_ATTRIBUTES = FILE_NOTIFY_CHANGE_ATTRIBUTES, //监视文件属性更改
		NOTIFY_SIZE = FILE_NOTIFY_CHANGE_SIZE, //监视文件大小更改
		NOTIFY_LAST_WRITE = FILE_NOTIFY_CHANGE_LAST_WRITE, //监视文件最后写入时间更改
		NOTIFY_LAST_ACCESS = FILE_NOTIFY_CHANGE_LAST_ACCESS, //监视文件最后访问时间更改
		NOTIFY_CREATION = FILE_NOTIFY_CHANGE_CREATION, //监视文件创建
		NOTIFY_SECURITY = FILE_NOTIFY_CHANGE_SECURITY, //监视文件安全描述符更改
		NOTIFY_ALL = NOTIFY_DIR_NAME | NOTIFY_FILE_NAME | NOTIFY_SIZE | NOTIFY_LAST_WRITE | NOTIFY_LAST_ACCESS | NOTIFY_CREATION | NOTIFY_ATTRIBUTES | NOTIFY_SECURITY //监视所有情况
	};
	//发生的行为
	enum {
		ACTION_ADD = FILE_ACTION_ADDED, //文件添加
		ACTION_REMOVE = FILE_ACTION_REMOVED, //文件删除
		ACTION_MODIFIED = FILE_ACTION_MODIFIED, //文件更改
		ACTION_RENAME_OLD = FILE_ACTION_RENAMED_OLD_NAME, //文件重命名（旧名字）
		ACTION_RENAME_NEW = FILE_ACTION_RENAMED_NEW_NAME //文件重命名（新名字）
	};
public:
	WatchFolder(int bufSize = 4096) {
		m_hFile = nullptr;
		m_buf = new char[bufSize];
	}
	~WatchFolder()
	{
		Close();
		delete[] m_buf;
	}
	/**
	 * @brief 初始化要进行监视的文件
	 * @param dir
	 * @return
	*/
	bool Init(const std::wstring& dir) {

		if (_waccess(dir.c_str(), 0) != 0)
			FileTool::createDirectory(dir);

		if (m_hFile != nullptr) {
			CloseHandle(m_hFile);
			m_hFile = nullptr;
		}
		//打开文件
		m_hFile = CreateFileW(dir.data(), FILE_LIST_DIRECTORY, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, 0, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, 0);
		return m_hFile != INVALID_HANDLE_VALUE;
	}
	/**
	 * @brief 关闭打开的文件句柄
	*/
	void Close() {
		if (m_hFile != NULL)	CloseHandle(m_hFile);
	}
	/**
	 * @brief 开始监视文件夹
	 * @param fileInfo 返回发生改变的文件信息
	 * @param filter 要进行监视的文件行为，可使用WatchFolder::NOTIFY_*
	 * @param IsWatchSubTree 是否监视子目录
	 * @return 存在文件更改信息返回true，否则返回false
	*/
	bool BeginMonitorRenameEvent()
	{
		bool retVal = false;
		DWORD lbyte;
		
		while (true)
		{
			if (!ReadDirectoryChangesW(m_hFile, m_buf, 4096, FALSE, FILE_NOTIFY_CHANGE_FILE_NAME, &lbyte, NULL, NULL))
				return retVal; //失败

			cout << "Directory Changed." << endl;

			FILE_NOTIFY_INFORMATION* f = (FILE_NOTIFY_INFORMATION*)m_buf; //得到FILE_NOTIFY_INFORMATION结构体，进行解析

			do
			{
				auto wchar_size = sizeof(wchar_t);
				auto len = f->FileNameLength + wchar_size;

				wchar_t* fileName = new wchar_t[len];
				memcpy(fileName, f->FileName, f->FileNameLength);

				if (f->Action == FILE_ACTION_RENAMED_OLD_NAME)
				{
					wcout << L"Old File Name:" << fileName << endl;
					retVal = true;
				}

				if (f->Action == FILE_ACTION_RENAMED_NEW_NAME)
				{
					wcout << L"New File Name:" << fileName << endl;
					retVal = true;
				}

				delete[] fileName;

				if (0 == f->NextEntryOffset)
					break;

				f = (FILE_NOTIFY_INFORMATION*)((char*)f + f->NextEntryOffset);

			} while (true);

			if (retVal)
				return retVal;
		}	
		
	}
};